// Targil4.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
# include <string.h>
# include <stdio.h>
# include <stdlib.h>
# include <conio.h>

// Compatibility for C
#define scanf	scanf_s
#define getche	_getche
////////////////////////

char testText[] = "The best trick the devil ever pulled was convincing the world it didn't exist. And then, puff like that he is gone.\n";
char isAlphabetical(char c)
{
	if((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z'))
		return 1;
	else
		return 0;
}

/*
char * DeleteWordFromText(char *pTxt, int len, char *word)
{
	int i,j;
	char *pTempBuffer = (char*)malloc(len+1);
	int wordlen = strlen(word);
	int iMatchedCharacters = 0;
	pTempBuffer[0] = 0; // NULL termination. 
	if(wordlen>len)
	{
		printf("Error: word is longer than the whole text.\n");
		return pTxt; // Leave the text as is...
	}
	// Find if the word exist
	for(i=0;i<len;i++)
	{
		if(iMatchedCharacters < wordlen && pTxt[i] == word[iMatchedCharacters])
		{
			iMatchedCharacters++;
			if(iMatchedCharacters == wordlen && 
				(i+1<len) && !isAlphabetical(pTxt[i+1])) // Make sure it is a whole word and there is a non character after wordlen
			{ // Found an appearance of the word.
				//printf("Found %s at location %d\n",word,i-wordlen);
				strcpy(pTempBuffer,pTxt);	// Use a temporary buffer because the behavior of strcat is undefined if the source and destination strings overlap.
				pTempBuffer[i-wordlen] = 0; // cut all the rest of the string beyond this point
				strcat(pTempBuffer,pTxt+i+1);
				len -= wordlen;
				strcpy(pTxt,pTempBuffer); // Copy the short string back to original buffer.
				pTempBuffer[0] = 0;		// Clean temp buffer for next appearance of the word
			}
		}
		else
			iMatchedCharacters = 0; // Start from the beginning
	}
	
	free(pTempBuffer);			// Release the initial big temporary buffer
	pTempBuffer = (char*)malloc(len+1);// Allocate shorter buffer for the shorter string
	strcpy(pTempBuffer,pTxt);	// Copy the string into the new shorter buffer.
	free(pTxt);					// Release original memory
	return pTempBuffer;			// Return the new buffer

}
*/

typedef enum
{
	PM_PRINT_STAT,
	PM_PRINT_WORD_BY_IDX,
	PM_ADD_WORD_AFTER_IDX,
	PM_DEL_WORD_FROM_TEXT,
	PM_REPLACE_WORD
}ProcessModeEnum;

char *ProcessText(char *pTxt, int len, int iWordIndex, char *word, char *newWord, ProcessModeEnum	pm)
{
	int i;
	int iTotalCapitalLetters = 0;
	int iTotalSmallLetters = 0;
	int iWordCount = 0;
	char bStartOfWord = 0; // Boolean flag
	char *pPointToTheOutputWord = 0;
	int  iOutputWordLength = 0;
	char *pPointToCurrentWord = 0;
	int  iCurrentLetterCount = 0;
	char *pTempBuffer = NULL;
	int iWordLen ;
	int iNewWordLen ;

	if(word) iWordLen = strlen(word);
	if(newWord) iNewWordLen = strlen(newWord);


	for(i = 0; i<len; i++)
	{ // Scan each letter in text
		if(isAlphabetical(pTxt[i]))
		{
			if(bStartOfWord == 0)
				pPointToCurrentWord = &pTxt[i]; // Save the position of the current word
			bStartOfWord = 1;
			iCurrentLetterCount++;

			if(pTxt[i] <= 'Z')
				iTotalCapitalLetters++;
			else 
				iTotalSmallLetters++;
		}
		else if(pTxt[i] == ' ' || 
				pTxt[i] == '.' ||
				pTxt[i] == ',' ||
				pTxt[i] == '?' ||
				pTxt[i] == '!' ||
				pTxt[i] == ':' ||
				pTxt[i] == '\r'
				)
		{
			if(bStartOfWord)
			{	// Start of word was previously detected and now we found a non letter symbol so we clear the flag and increment the word count.
				bStartOfWord = 0;
				iWordCount++;
				if(pm == PM_PRINT_STAT) 
				{
					if(iOutputWordLength < iCurrentLetterCount)
					{ // Save a pointer to the current known longest word and save its length.
						iOutputWordLength = iCurrentLetterCount;
						pPointToTheOutputWord = pPointToCurrentWord;
					}
				}
				else if(pm == PM_PRINT_WORD_BY_IDX)
				{
					if(iWordCount == iWordIndex)
					{
						iOutputWordLength = iCurrentLetterCount;
						pPointToTheOutputWord = pPointToCurrentWord;
						break;
					}
				}
				else if(pm == PM_ADD_WORD_AFTER_IDX)
				{
					if(iWordCount == iWordIndex)
					{
						pTempBuffer = (char*)malloc(len+1+iWordLen+1);
						strncpy(pTempBuffer,pTxt,i);
						pTempBuffer[i] = 0;
						strcat(pTempBuffer," ");
						strcat(pTempBuffer,word);
						strcat(pTempBuffer,&pTxt[i]);
						free(pTxt);
						break;
					}
				}
				else if(pm == PM_REPLACE_WORD)
				{
					pTempBuffer = pTxt; // Temp
					// Check if current word match
					if(iCurrentLetterCount == iWordLen && strncmp(&pTxt[i-iCurrentLetterCount],word,iCurrentLetterCount) == 0)
					{
						int iTotalNewBuffer = len - iWordLen + iNewWordLen;
						pTempBuffer = (char*)malloc(iTotalNewBuffer+1);
						pTempBuffer[0] = 0;							// Put a null termination at the beginning so next call to strcat will work. 
						strncat(pTempBuffer,pTxt,i-iWordLen);		// Copy first string part (up to word)
						strcat(pTempBuffer,newWord);				// Concatenate new word
						strcat(pTempBuffer,&pTxt[i]);				// Concatenate rest of the string (after word)
						free(pTxt);									// free previous buffer
						pTxt = (char*)malloc(iTotalNewBuffer+1);	// Allocate new one according new size
						strcpy(pTxt,pTempBuffer);					// Copy new string from temp buffer
						free(pTempBuffer);							// free temp buffer.
						len = iTotalNewBuffer;		  // Update len
						i = i+(iNewWordLen-iWordLen); // Update current position.
					}
				}
				else if(pm == PM_DEL_WORD_FROM_TEXT)
				{
					pTempBuffer = pTxt; // Temp
					// Check if current word match
					if(iCurrentLetterCount == iWordLen && strncmp(&pTxt[i-iCurrentLetterCount],word,iCurrentLetterCount) == 0)
					{
						int iTotalNewBuffer;
						iTotalNewBuffer = len - iWordLen; 
						pTempBuffer = (char*)malloc(iTotalNewBuffer+1);
						pTempBuffer[0] = 0;							// Put a null termination at the beginning so next call to strcat will work. 
						strncat(pTempBuffer,pTxt,i-iWordLen);		// Copy first string part (up to word)
						strcat(pTempBuffer,&pTxt[i]);				// Concatenate rest of the string (after word)
						free(pTxt);									// free previous buffer
						pTxt = (char*)malloc(iTotalNewBuffer+1);	// Allocate new one according new size
						strcpy(pTxt,pTempBuffer);					// Copy new string from temp buffer
						free(pTempBuffer);							// free temp buffer.
						len = iTotalNewBuffer;						// Update len
						i = i-iWordLen;								// Update current position.
					}
				}

				iCurrentLetterCount = 0;
			}
		}
	}

	if(pm == PM_PRINT_STAT)
	{
		printf("Total capital letters in text: %d\n",iTotalCapitalLetters);
		printf("Total small letters in text: %d\n",iTotalSmallLetters);
		printf("Total word count is: %d\n",iWordCount);
		if(iWordCount)
		{ // If the text had any word inside, print the longest:
			pPointToCurrentWord = (char*)malloc(iOutputWordLength+1);
			strncpy(pPointToCurrentWord,pPointToTheOutputWord,iOutputWordLength);
			pPointToCurrentWord[iOutputWordLength] = 0; // Put null termination
			printf("The longest word found is: %s\n",pPointToCurrentWord);
			printf("The longest word length is: %d\n",iOutputWordLength);
			free(pPointToCurrentWord);
		}
		return NULL;
	}
	else if(pm == PM_PRINT_WORD_BY_IDX)
	{
		if(iWordIndex > iWordCount)
			printf("The requested word index exceeds total word count.\n");
		else
		{
			pPointToCurrentWord = (char*)malloc(iOutputWordLength+1);
			strncpy(pPointToCurrentWord,pPointToTheOutputWord,iOutputWordLength);
			pPointToCurrentWord[iOutputWordLength] = 0; // Put null termination
			printf("The requested word is: %s\n",pPointToCurrentWord);
			free(pPointToCurrentWord);
		}
		return NULL;
	}
	else if(pm == PM_ADD_WORD_AFTER_IDX)
	{
		if(iWordCount != iWordIndex) // Maybe index was too big...
			return pTxt; // Return current allocated buffer of pTxt.
		else
			return pTempBuffer;
	}
	return pTxt;
}

char * DeleteWordFromText(char *pTxt, int len, char *word)
{
	return ProcessText(pTxt,len,0,word,NULL,PM_DEL_WORD_FROM_TEXT);
}

void PrintTextStatistics(char *pTxt, int len)
{
	ProcessText(pTxt,len,0,NULL,NULL,PM_PRINT_STAT);
}

void PrintWordIndexFromText(char *pTxt, int len, int idx)
{
	ProcessText(pTxt,len,idx,NULL,NULL,PM_PRINT_WORD_BY_IDX);
}

char * AddWordToText(char *pTxt, int len,int idx, char *word)
{
	return ProcessText(pTxt,len,idx,word,NULL,PM_ADD_WORD_AFTER_IDX);
}

char * ReplaceWordInText(char *pTxt, int len, char *word, char *newWord)
{
	return ProcessText(pTxt,len,0,word,newWord,PM_REPLACE_WORD);
}

void GetUserInput(char *msg,char *strData)
{
	printf ("%s ",msg);
	gets (strData);
}
// Menu function - to use after initial phase
void LoopMenu(char *inputText)
{

	char cMenuOpt='E';
	int  i,iTextLen = strlen(inputText);
	char userWord[256]; // Assuming maximum word len of 256
	char userIndex[256]; // Assuming maximum index len of 256

	char *pText = (char*)malloc(iTextLen+1); // The +1 is needed for null termination.
	strcpy(pText,inputText); // Copy input text to a local dynamically allocated memory.
	do 
	{

		printf("Choose an option from the menu below:\n");
		printf("\t 1 - Print text statistics\n");
		printf("\t 2 - Get word by index\n");
		printf("\t 3 - Delete word from text\n");
		printf("\t 4 - Add word to text\n");
		printf("\t 5 - Replace word in text\n");
		printf("\t E - Exit program\n");
		fflush(stdin);
		cMenuOpt=getche();

		printf("\n");

		switch (cMenuOpt)
		{
		case '1': // Print text statistics
			PrintTextStatistics(pText,iTextLen); 
			break;
		case '2': //Get word by index
			GetUserInput("Enter word index: ",userIndex);
			i = atoi(userIndex);
			if(i)
				PrintWordIndexFromText(pText,iTextLen,i); 
			else
				printf("%s is illegal value.\n",userIndex);
			break;
		case '3': //Delete word from text 
			GetUserInput("Enter word to delete: ",userWord);
			pText = DeleteWordFromText(pText,iTextLen,userWord);
			iTextLen = strlen(pText); // Update current text length
			printf("Text after delete:\n%s\n",pText);
			break;
		case '4': //Add word to text
			GetUserInput("Enter word to be added: ",userWord);
			GetUserInput("\nEnter word index: ",userIndex);
			i = atoi(userIndex);
			if(i)
			{
				pText = AddWordToText(pText,iTextLen,i,userWord); // Add "the" after word index #3
				iTextLen = strlen(pText); // Update current text length
				printf("Text after Addition:\n%s\n",pText);
			}
			else
				printf("%s is illegal value for word index.\n",userIndex);

			break;
		case '5': //Replace word in text
			GetUserInput("Enter word to be replaced: ",userWord);
			GetUserInput("\nEnter new word: ",userIndex);

			pText = ReplaceWordInText(pText,iTextLen,userWord, userIndex);
			iTextLen = strlen(pText); // Update current text length
			printf("Text after Replacment:\n%s\n",pText);
			break;
		case 'e': // Normal program termination
		case 'E': // Normal program termination
			printf("\n\nBYE\n\n");
			cMenuOpt='E';
			break;
		default:		//Invalid Option ask again
			printf("Value unacceptable for this menu\n\n");
		}
	} while (cMenuOpt != 'E' );
	free(pText);
}
#define INITIAL_MALLOC_SIZE	8
int _tmain(int argc, _TCHAR* argv[])
{
	int  iMallocSize = INITIAL_MALLOC_SIZE;
	char *pUserText = (char*)malloc(iMallocSize);
	char cInputChar = 0;
	int   iChCnt = 0;
	printf("Please enter your text message:\n");
	// Ask user to input some text...
	while(1){
		fflush(stdin);
		cInputChar=getche();
		pUserText[iChCnt++] = cInputChar;
		if(cInputChar == '\r')
			break;

		if(iChCnt == iMallocSize-1) // Need to save space for the null termination
		{
			char *pNewBuffer;
			iMallocSize *= 2;
			pNewBuffer = (char*)malloc(iMallocSize);
			memcpy(pNewBuffer,pUserText,iChCnt);
			free(pUserText);
			pUserText = pNewBuffer;
		}
	}
	pUserText[iChCnt] = 0; // Null termination
	printf("%s\n",pUserText);
	//LoopMenu(testText);
	LoopMenu(pUserText);
	free(pUserText);
	return 0;
}

